<template>
  <div
    ref="scrollBody"
    style="height: 100%"
  >
    <el-scrollbar style="height: 100%;width: 100%;padding-bottom: 15px;">
      <div class="erp-page-form-body">
        <erp-form
          ref="erpForm"
          :model="form"
          @submit.native.prevent
        >
          <div
            ref="groupForm"
            class="groupForm"
          >
            <div
              v-for="(groupItem, groupIndex) in groupForm"
              :key="groupIndex"
              class="form-group erp-list__form"
            >
              <div
                v-for="(box, boxIndex) in groupItem.items"
                :key="boxIndex"
                class="form-box"
              >
                <div
                  v-if="box.title"
                  class="form-box-header"
                >
                  <span class="form-box-header-icon" /> {{ box.title }}
                </div>
                <el-row>
                  <template v-for="(item, index) in box.items">
                    <erp-item
                      :key="index"
                      :item="item"
                      :form-item-style="formItemStyle"
                      :form="form"
                      @update-field="handleUpdateField"
                      @value-change="handleValueChange"
                    />
                  </template>
                </el-row>
              </div>
            </div>
          </div>
          <div class="erp-detail-table">
            <div
              v-if="hasDetailTable"
              class="form-group erp-list__form"
            >
              <div class="form-box">
                <div class="form-box-header">
                  <span class="form-box-header-icon" /> {{ detailTableGroupTitle }}
                  <el-button
                    v-if="editable"
                    type="text"
                    style="margin-left: 15px;"
                    icon="el-icon-circle-plus-outline"
                    @click="addDetailItems"
                  >
                    新增明细
                  </el-button>
                </div>
                <component
                  :is="detailTableComponent"
                  ref="detailTable"
                  :visible="visibleDetail"
                  :api-list="detailTableApiList"
                  :list="form[listField]"
                  :height="detailTableMaxHeight"
                  :form="form"
                  :is-new-record="isNewRecord"
                  :editable="editable"
                  :is-copy="isCopy"
                  @clear="clearTable"
                />
              </div>
            </div>
            <div
              v-if="showApproveHistory"
              class="form-group erp-list__form"
            >
              <div class="form-box">
                <div
                  v-if="approveTitle"
                  class="form-box-header"
                >
                  <span class="form-box-header-icon" /> {{ approveTitle }}
                </div>
                <approve-history
                  :id="query ? query.id : null"
                  ref="approveHistory"
                  :type="approveType"
                  :change-flag="visibleApproveHistory"
                />
              </div>
            </div>
          </div>
        </erp-form>
        <slot name="default" />
      </div>
    </el-scrollbar>
  </div>
</template>

<script>
/**
 * erp业务表单包含主从结构
 * @author maolin
 */
import ErpForm from '@/components/erp/ErpListForm/ErpForm';
import ErpItem from '@/components/erp/ErpListForm/ErpItem';
import ApproveHistory from '@/components/ApproveHistory';
import elementResizeDetectorMaker from "element-resize-detector";
import {generateGroupForm, getComponentByPath, toast, cloneJson} from "../../../utils";
import {generateNewForm, getServerDataSource, getServerDefaultValue} from "../../../utils/form";
import {base as request} from '@/request';
import {optType} from "../ErpBusinessPage/config";

export default {
  name: "ErpBusinessForm",
  components: {
    ErpForm,
    ErpItem,
    ApproveHistory,
  },
  beforeRouteLeave (to, from, next) {
    if (this.createTimer) {
      clearInterval(this.createTimer);
    }
    if (this.approveHistoryTimer) {
      clearTimeout(this.approveHistoryTimer);
    }
    next();
  },
  props: {
    /**
     * 审批类型
     * @public
     */
    approveType: {
      type: [Number, String],
      default: ''
    },
    /**
     * 标题
     * @public
     */
    title: {
      type: String,
      default: ''
    },
    /**
     * 是否显示
     * @public
     */
    visible: {
      type: Boolean,
      default: false
    },
    /**
     * 是否是新纪录
     * @public
     */
    isNewRecord: {
      type: Boolean,
      default: true
    },
    /**
     * 当前是否为复制
     * @public
     */
    isCopy: {
      type: Boolean,
      default: false
    },
    /**
     * 是否可编辑
     * @public
     */
    editable: {
      type: Boolean,
      default: true
    },
    /**
     * 配置对象
     * @public
     */
    options: {
      type: Object,
      default () {
        return {};
      }
    },
    /**
     * 额外参数
     * @public
     */
    query: {
      type: Object,
      default () {
        return {};
      }
    }
  },
  data() {
    return {
      loading: false,
      visibleDetail: false,
      form: {},
      visibleApproveHistory: false,
      formConfigList: [],
      detailTableComponent: null,
      detailTableMaxHeight: 0,
      denyContent: null,
      recordOldValue: {
        width: '0',
        height: '0'
      }
    };
  },
  computed: {
    // 自定义验证
    customValidate () {
      return function (e) {
        return this.options && this.options.customValidate ? this.options.customValidate(e) : null;
      };
    },
    listField () {
      return this.options && this.options.listField ? this.options.listField : 'list';
    },
    shouldApprove () {
      const approveStatus = this.$store.state.approve.approveStatus;
      return approveStatus[this.approveType] ? approveStatus[this.approveType] : false;
    },
    formItemStyle () {
      return this.options && this.options.formItemStyle ? this.options.formItemStyle : {};
    },
    groupForm () {
      return generateGroupForm(this.formConfigList);
    },
    footButtons () {
      let buttons = this.options && this.options.buttons ? this.options.buttons : [];
      return buttons.filter(item => {
        return item.position === 'foot';
      });
    },
    hasDetailTable () {
      return this.options && this.options.detailTable && this.options.detailTable.enable !== false;
    },
    detailTableApiList () {
      return this.options && this.options.detailTable && this.options.detailTable.apiList ? this.options.detailTable.apiList : null;
    },
    detailTablePath () {
      return this.options && this.options.detailTable && this.options.detailTable.path ? this.options.detailTable.path : null;
    },
    detailTableGroupTitle () {
      return this.options && this.options.detailTable && this.options.detailTable.groupTitle ? this.options.detailTable.groupTitle : "明细项";
    },
    approveTitle () {
      return this.options && this.options.approveHistory && this.options.approveHistory.groupTitle ? this.options.approveHistory.groupTitle : "审核记录";
    },
    dataSourceApi () {
      return this.options && this.options.apiList && this.options.apiList.dataSourceApi ? this.options.apiList.dataSourceApi : null;
    },
    defaultValueApi () {
      return this.options && this.options.apiList && this.options.apiList.defaultValueApi ? this.options.apiList.defaultValueApi : null;
    },
    preViewFunction () {
      return this.options && this.options.preViewFunction ? this.options.preViewFunction : '';
    },
    showApproveHistory () {
      return !!(this.options && this.options.approveHistory && this.options.approveHistory.enable === true);
    },
  },
  watch: {
    visible: {
      handler (visible, oldVisible) {
        if (visible && visible !== oldVisible) {
          this.visibleDetail = visible;
          this.getInit();
          this.visibleApproveHistory = !this.visibleApproveHistory;
        }

      },
      immediate: true
    },
    loading (loading) {
      this.$emit('change-loading', loading);
    }
  },
  created() {
  },
  mounted() {
  },
  beforeDestroy() {
    if (this.createTimer) {
      clearInterval(this.createTimer);
    }
    if (this.approveHistoryTimer) {
      clearTimeout(this.approveHistoryTimer);
    }
  },
  methods: {
    /**
     * 观察表单高度变化
     * @public
     */
    observerFormHeight () {
      let erd = elementResizeDetectorMaker();
      erd.listenTo(this.$refs.groupForm, (element) => { // 这里的this.$refs.xxx指定要监听的元素对象，对应的是<div ref="xxx"></div>
        let height = element.offsetHeight;
        if (height != this.recordOldValue.height) {
          this.setDetailTableHeight(height);
        }
      });
    },
    /**
     * 关闭当前表单
     * @public
     */
    handleClose () {
      this.$emit('close');
    },
    /**
     * 更新表单字段
     * @param {object} fieldObj 表单字段对象,{表单字段1:对应的值, 表单字段2:对应的值}
     * @public
     */
    handleUpdateField (fieldObj){
      let form = this.form;
      if (form) {
        for (let i in form) {
          if (fieldObj[i] !== undefined) {
            form[i] = fieldObj[i];
          }
        }
      }
    },
    /**
     * 改变某个字段的值
     * @param {object} obj 值对象,{field:字段名, value:字段值}
     * @public
     */
    handleValueChange (obj) {
      let form = this.form;
      if (obj.field) {
        form[obj.field] = obj.value;
      }
      this.$store.dispatch('erp/changeSelectId', obj);
    },
    /**
     * 计算并改变tab面板的高度
     * @private
     */
    fetchTabPaneHeight () {
      this.$nextTick(() => {
        if (this.$refs.scrollBody) {
          let height = this.$refs.scrollBody.parentNode.offsetHeight;
          height = height - 55 - 24;
          this.tabPaneHeight = height;
        }
      });
    },
    /**
     * 初始化表单,生成表单
     * @public
     */
    async getInit() {
      let formConfigList = await this.getServerDataSource(this.options.form);
      formConfigList = await this.getDefaultValue(formConfigList);
      this.formConfigList = formConfigList;
      this.form = this.generateNewForm(this.formConfigList);
      this.detailTableComponent = getComponentByPath(this.detailTablePath);
      this.$nextTick(() => {
        this.$refs.erpForm.clearValidate();
        if (this.editable) {
          this.observerFormHeight();
        }
        if (this.hasDetailTable &&  this.detailTableComponent) {
          this.createTimer = setInterval(() => {
            if (this.$refs.detailTable) {
              clearInterval(this.createTimer);
              this.getInitDetailTable();
            }
          },100);
        }
      });
    },
    /**
     * 清除从表表格数据
     * @public
     */
    clearTable () {
      this.getInitDetailTable(false);
    },
    /**
     * 初始化从表表数据
     * @public
     */
    getInitDetailTable (onlyCreate = true) {
      if (this.editable) {
        let height = this.$refs.groupForm.offsetHeight;
        this.setDetailTableHeight(height);
        if (onlyCreate) {
          if (this.isNewRecord && !this.isCopy) {
            this.compEmptyTableData();
          }
        } else {
          this.compEmptyTableData();
        }
      }
    },
    /**
     * 计算高度并填充表格
     * @public
     */
    compEmptyTableData () {
      // 表头和底部滚动条的高度
      const rest = 110;
      // 每格表格的高度，当前以最小字体来计算
      const cellHeight = 26;
      // 计算需要填充空表格的数量
      let len = Math.floor((this.detailTableMaxHeight - rest) / cellHeight);
      this.$refs.detailTable.$refs.table.resetInsertData(len);
    },
    /**
     * 设置从表表格高度
     * @param {number} formHeight 表单高度
     * @public
     */
    setDetailTableHeight (formHeight) {
      const totalHeight = this.$refs.scrollBody.parentNode.offsetHeight;
      let detailTableMaxHeight = totalHeight - formHeight - 100;
      this.detailTableMaxHeight = detailTableMaxHeight <= 300 ? 300 : detailTableMaxHeight;
    },
    /**
     * 生成新表单,带初始值
     * @param {array} formList 表单列表
     * @public
     */
    generateNewForm (formList) {
      return generateNewForm(formList, this.query, this.form);
    },
    /**
     * 从服务端获取表单项的选项和表单项的默认值
     * @param {array} formList 表单配置列表
     * 
     * @public
     */
    getServerDataSource (formList) {
      return new Promise( (resolve, reject) => {
        getServerDataSource(formList, this.dataSourceApi, this.query, this.preViewFunction, '')
          .then((res) => {
            resolve(res.formList);
            console.log(res)
            return res.formList;
          })
          .catch(err => {
            console.log(err);
            resolve(formList);
            return formList;
          });
      });
    },
    /**
     * 从服务端获取表单项的默认值
     * @param {array} formList 表单配置列表
     * @public
     */
    getDefaultValue (formList) {
      return new Promise( (resolve, reject) => {
        getServerDefaultValue(this.defaultValueApi,formList,  this.query, this.preViewFunction)
          .then((res) => {
            resolve(res.formList);
            return res.formList;
          })
          .catch(err => {
            console.log(err);
            resolve(formList);
            return formList;
          });
      });
    },
    /**
     * 保存表单
     * @param {boolean} isContinue 是否继续添加
     * @param {boolean} hasDetailTable 是否包含从表
     * @param {object} button 按钮配置
     * @param {boolean} isSubmit 提交之后是否直接提交审批
     * @param {boolean} isDraft 是否保存为草稿状态
     * @private
     */
    handleSave ({isContinue, hasDetailTable, button, isSubmit, isDraft }) {
      isContinue === undefined ? isContinue = false : '';
      this.$refs.erpForm.validate((valid) => {
        // 验证主表
        if (valid) {
          let form = cloneJson(this.form);
          if (hasDetailTable) {
            const detailTable = this.$refs.detailTable.$refs.table;
            // 验证子表
            detailTable.validateDetail()
              .then(valid => {
                if (valid) {
                  let list = detailTable.getEffectTableData();
                  if (list.length < 1) {
                    toast({
                      message: '请添加明细',
                      type: 'error'
                    });
                    return false;
                  }
                  form[this.listField] = list;
                  if (this.customValidate) {
                    const customRes = this.customValidate({form});
                    if (customRes && !customRes.customValid) {
                      toast({
                        message: customRes.message,
                        type: 'error'
                      });
                      return false;
                    }
                  }
                  this.submitData({form,isContinue, button, isDraft, isSubmit});
                }
              });
          }else {
            this.submitData({form,isContinue, button, isDraft, isSubmit});
          }
          return false;
        } else {
          return false;
        }
      });
    },
    /**
     * 提交表单到服务端
     * @param {object} form 表单对象
     * @param {boolean} isContinue 是否继续添加
     * @param {object} button 按钮配置
     * @param {boolean} isSubmit 提交之后是否直接提交审批
     * @param {boolean} isDraft 是否保存为草稿状态
     * @private
     */
    submitData ({form, isContinue, button, isDraft, isSubmit}) {
      const url = button.actionApi ? button.actionApi.url : '';
      const query = button.actionApi ? button.actionApi.query : {};
      form = Object.assign(form, query);
      if (!url) {
        return false;
      }
      this.loading = true;
      let loading = toast({
        message: "正在请求...",
        type: "info",
        iconClass: "el-icon-loading",
        duration: 10000
      });
      request.post(url, form)
        .then(res => {
          if (!isDraft && !isSubmit) {
            loading.close();
            toast({
              message: '保存成功',
              type: 'success'
            });
          }
          if (isContinue) {
            // 保存并继续
            this.getInit();
            this.$emit('refresh');
            this.loading = false;
          } else if(isSubmit) {
            // 保存并提交
            this.applyForm(form.id, this.approveType);
          } else {
            // 保存
            this.handleClose();
            this.$emit('refresh');
            this.loading = false;
          }

        })
        .catch(() => {
          loading.close();
          this.loading = false;
        })
        .finally(() => {
          loading.close();
          this.loading = false;
        });
    },
    /**
     * 提交审核申请
     * @param {string|number} id 订单id
     * @param {number} approveType 审批类型
     * @private
     */
    applyForm (id, approveType) {
      let loading = toast({
        message: "正在请求...",
        type: "info",
        iconClass: "el-icon-loading",
        duration: 10000
      });
      request.post('/activitiController/application',{
        id: id,
        type: approveType
      })
        .then((res) => {
          loading.close();
          this.handleClose();
          this.$emit('refresh');
          this.loading = false;
        })
        .catch(() => {
          loading.close();
          this.loading = false;
        })
        .finally(() => {
          loading.close();
          this.loading = false;
        });
    },
    /**
     * 点击底部按钮触发
     * @param {object} button  按钮配置对象
     * @private
     */
    handleClickFootButton (button) {
      let hasDetailTable = this.hasDetailTable;
      if (button.actionType === 'save') {
        this.handleSave({isContinue:false, hasDetailTable, button} );
      } else if (button.actionType === 'saveAndContinue') {
        this.handleSave({isContinue:true, hasDetailTable, button});
      } else if (button.actionType === 'accessApprove') {
        this.handleApprove();
      } else if (button.actionType === 'denyApprove') {
        this.handleApprove(true);
      } else if (button.actionType === 'saveAndApply') {
        this.handleSave({isContinue:false, hasDetailTable, button, isSubmit: true});
      } else if (button.actionType === 'saveAndDraft') {
        this.handleSave({isContinue:false, hasDetailTable, button, isDraft: true});
      }
    },
    /**
     * 订单审核
     * @param {boolean} isDeny 是否拒绝申请
     * @public
     */
    handleApprove (isDeny) {
      if (isDeny === undefined) {
        isDeny = false;
      }
      if (!isDeny) {
        this.$prompt('同意备注', '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          inputPlaceholder: '备注',
          inputErrorMessage: '',
          inputType: 'textarea'
        }).then(({ value }) => {
          this.denyContent = value;
          this.submitApprove(isDeny);
        }).catch(() => {
        });
      } else {
        this.$prompt('请输入拒绝的原因', '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          inputPlaceholder: '原因',
          inputErrorMessage: '请输入拒绝的原因',
          inputType: 'textarea'
        }).then(({ value }) => {
          this.denyContent = value;
          this.submitApprove(isDeny);
        }).catch(() => {
        });
      }
    },
    /**
     * 提交申请到服务端
     * @param {boolean} isDeny 是否拒绝申请
     * @public
     */
    submitApprove (isDeny) {
      let opt = isDeny ? optType["REFUSE"].value : optType["AGREE"].value;
      if (isDeny && !this.denyContent) {
        toast({
          message: "请输入审批拒绝的理由",
          type: "error"
        });
        return false;
      }
      this.loading = true;
      let loading = toast({
        message: "正在提交...",
        type: "info",
        iconClass: "el-icon-loading",
        duration: 10000
      });
      request.post('/activitiController/excute', {
        "activiItemId": this.query.activiItemId,
        "id": this.query ? this.query.id : null,
        "opt": opt,
        "params": null,
        "remark": this.denyContent,
        "taskId": this.query.taskId,
        "type": this.approveType
      })
        .then(res => {
          loading.close();
          toast({
            message: '审批处理成功',
            type: "success"
          });
          this.$emit('refresh');
          this.$emit('update-approve-count');
          this.handleClose();
          this.loading = false;
        })
        .catch(() => {
          loading.close();
          this.loading = false;
        })
        .finally(() => {
          loading.close();
          this.loading = false;
        });
    },
    /**
     * 添加从表项
     * @public
     */
    addDetailItems () {
      this.$refs.detailTable.$refs.table.insertTable();
    }
  }
};
</script>

<style lang="scss" scoped>

</style>
